#include <stdio.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <stdlib.h>
#include <assert.h>

#include <openssl/bn.h>
#include <openssl/crypto.h>
#include <openssl/dsa.h>

#include <xmlsec/crypto.h>

int name(char *start, char *end, char *ptr) {
  char name[MAXDNAME];
  int ret;

  ret = dn_expand(start, end, ptr, name, MAXDNAME);
  if(ret == -1)
    exit(4);
  fprintf(stderr, "Name %s\n", name);
  return ret;
}

DSA *getKey(char *dest) {
  union {
    HEADER h;
    char r[1000];
  } s;
  int rlen, qd, an, ns, ar, i;
  unsigned char *ptr = s.r;
  DSA *ret;
  
  ret = NULL;
  fprintf(stderr, "Querying %s\n", dest);
  rlen = res_query(dest, C_IN, T_KEY, s.r, 999);
  fprintf(stderr, "Returned %d\n", rlen);
  qd = ntohs(s.h.qdcount);
  an = ntohs(s.h.ancount);
  ns = ntohs(s.h.nscount);
  ar = ntohs(s.h.arcount);
  fprintf(stderr, "qd %d an %d ns %d ar %d\n", qd, an, ns, ar);
  ptr += sizeof(HEADER);
  for(i = 0; i < qd; i++) {
    fprintf(stderr, "Query %d: ", i);
    ptr += name(s.r, s.r + 1000, ptr) + NS_QFIXEDSZ;
  }
  for(i = 0; i < an; i++) {
    int rdlength;
    unsigned int type, class;
    fprintf(stderr, "Answer %d: ", i);
    ptr += name(s.r, s.r + 1000, ptr);
    fprintf(stderr, "type %x class %x ttl %d\n", type = ntohs(*(u_int16_t *)ptr), class = ntohs(*(u_int16_t *)(ptr + 2)), ntohl(*(u_int32_t *)(ptr + 4)));
    ptr += 8;
    rdlength = ntohs(*(u_int16_t *)ptr);
    ptr += 2;
    fprintf(stderr, "%d bytes extra\n", rdlength);
    if(type == 25 && class == 1) {
      unsigned int flags, proto, alg;
      flags = ntohs(*(u_int16_t *)ptr);
      ptr += 2;
      proto = *ptr++;
      alg = *ptr++;
      fprintf(stderr, "Parsing IN KEY flags %x proto %x alg %x\n", flags, proto, alg);
      if(proto == 3 && alg == 3) {
	unsigned int t, size;
	unsigned char *str, *p = ptr;
	ret = DSA_new();
	
	fprintf(stderr, "Parsing DSA key\n");
	t = *p++;
	size = t * 8 + 64;
	fprintf(stderr, "T: %d\n", t);
	ret->q = BN_bin2bn(p, 20, NULL);
	p += 20;
	str = BN_bn2dec(ret->q);
	fprintf(stderr, "ret->q: %s\n", str);
	OPENSSL_free(str);
	ret->p = BN_bin2bn(p, size, NULL);
	p += size;
	str = BN_bn2dec(ret->p);
	fprintf(stderr, "P: %s\n", str);
	OPENSSL_free(str);
	ret->g = BN_bin2bn(p, size, NULL);
	p += size;
	str = BN_bn2dec(ret->g);
	fprintf(stderr, "G: %s\n", str);
	OPENSSL_free(str);
	ret->pub_key = BN_bin2bn(p, size, NULL);
	p += size;
	str = BN_bn2dec(ret->pub_key);
	fprintf(stderr, "Y: %s\n", str);
	OPENSSL_free(str);
	fprintf(stderr, "ptr %p p %p next %p len %d\n", ptr, p, ptr + rdlength, rdlength);
      }
      ptr -= 4;
    }
    ptr += rdlength;
  }
  for(i = 0; i < ns; i++) {
    int rdlength;
    fprintf(stderr, "Nameserver %d: ", i);
    ptr += name(s.r, s.r + 1000, ptr);
    fprintf(stderr, "type %x class %x ttl %d\n", ntohs(*(u_int16_t *)ptr), ntohs(*(u_int16_t *)(ptr + 2)), ntohl(*(u_int32_t *)(ptr + 4)));
    ptr += 8;
    rdlength = ntohs(*(u_int16_t *)ptr);
    ptr += 2;
    fprintf(stderr, "%d bytes extra\n", rdlength);
    ptr += rdlength;
  }
  for(i = 0; i < ar; i++) {
    int rdlength;
    fprintf(stderr, "Additional %d: ", i);
    ptr += name(s.r, s.r + 1000, ptr);
    fprintf(stderr, "type %x class %x ttl %d\n", ntohs(*(u_int16_t *)ptr), ntohs(*(u_int16_t *)(ptr + 2)), ntohl(*(u_int32_t *)(ptr + 4)));
    ptr += 8;
    rdlength = ntohs(*(u_int16_t *)ptr);
    ptr += 2;
    fprintf(stderr, "%d bytes extra\n", rdlength);
    ptr += rdlength;
  }
  s.r[rlen] = 0;
  return ret;
}

xmlSecKeyPtr getDNSKey(char *dest) {
  DSA *key;
  xmlSecKeyPtr ret;

  key = getKey(dest);
  if(!key)
    return NULL;
  ret = xmlSecKeyCreate();
  xmlSecKeySetValue(ret, xmlSecKeyDataCreate(xmlSecKeyDataDsaId));
  assert(!xmlSecOpenSSLKeyDataDsaAdoptDsa(xmlSecKeyGetValue(ret), key));
  return ret;
}
